package com.rmlowe.tincan;

import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONTokener;

public final class Statement {
	public final String id;
	public final Agent actor;
	public final Verb verb;

	private Statement(final String id, final Agent actor, final Verb verb) {
		this.id = id;
		this.actor = actor;
		this.verb = verb;
	}

	public static Statement parse(final InputStream in) throws IOException {
		try {
			return statement(new JSONObject(new JSONTokener(in)));
		} catch (final JSONException e) {
			throw new IOException(e);
		}
	}

	private static Statement statement(final JSONObject obj) {
		return new Statement(stringOrNull(obj, "id"),
				agent(obj.optJSONObject("actor")),
				new Verb(URI.create(stringOrNull(obj.optJSONObject("verb"),
						"id"))));
	}

	private static Agent agent(final JSONObject obj) {
		return new Agent(ObjectType.of(stringOrNull(obj, "objectType")),
				stringOrNull(obj, "name"), stringOrNull(obj, "mbox"),
				stringOrNull(obj, "mbox_sha1sum"), uriOrNull(stringOrNull(obj,
						"openid")), account(obj.optJSONObject("account")),
				members(obj.optJSONArray("member")));
	}

	private static URI uriOrNull(final String openid) {
		return openid == null ? null : URI.create(openid);
	}

	private static List<Agent> members(final JSONArray array) {
		if (array == null) {
			return null;
		} else {
			final List<Agent> result = new ArrayList<Agent>();
			for (int i = 0; i < array.length(); i++) {
				result.add(agent(array.optJSONObject(i)));
			}
			return result;
		}
	}

	private static Account account(final JSONObject obj) {
		return obj == null ? null : new Account(URI.create(stringOrNull(obj,
				"homePage")), stringOrNull(obj, "name"));
	}

	private static String stringOrNull(final JSONObject obj, final String key) {
		return obj.optString(key, null);
	}
}
